{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from scipy.signal import convolve2d"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# image 3x3 and filter 3x3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(3, 3)"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "image = np.array([[1, 2, 3],\n",
    "                  [4, 5, 6],\n",
    "                  [7, 8, 9]])\n",
    "\n",
    "filtr = np.array([[-1, -2, -1],\n",
    "                  [0, 0, 0],\n",
    "                  [1, 2, 1]])\n",
    "image.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-1, -2, -1],\n",
       "       [ 0,  0,  0],\n",
       "       [ 1,  2,  1]])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "filtr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1,  2,  1],\n",
       "       [ 0,  0,  0],\n",
       "       [-1, -2, -1]])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.rot90(filtr, k=2) # rotate 180 degree"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def conv2d(image, filtr, mode = 'same'):\n",
    "    filtr = np.rot90(filtr, 2) # rotate 180 degree\n",
    "    image_row, image_col = image.shape\n",
    "    filtr_row, filtr_col = filtr.shape\n",
    "    if mode == 'full':\n",
    "        zeros = np.zeros((filtr_row-1, image_col))\n",
    "        extimg = np.vstack((zeros, image, zeros))\n",
    "        zeros = np.zeros((extimg.shape[0], filtr_col-1))\n",
    "        extimg = np.column_stack((zeros, extimg, zeros))\n",
    "    elif mode == 'same':\n",
    "        zeros = np.zeros((int(filtr_row/2), image_col))\n",
    "        extimg = np.vstack((zeros, image, zeros))\n",
    "        zeros = np.zeros((extimg.shape[0], int(filtr_col/2)))\n",
    "        extimg = np.column_stack((zeros, extimg, zeros))\n",
    "    else:\n",
    "        extimg = image\n",
    "        \n",
    "    print(extimg)\n",
    "        \n",
    "    row_start, row_end = 0, extimg.shape[0]-filtr.shape[0]+1\n",
    "    col_start, col_end = 0, extimg.shape[1]-filtr.shape[1]+1\n",
    "    result = np.zeros((row_end, col_end))\n",
    "    for r in range(row_start, row_end):\n",
    "        for c in range(col_start, col_end):\n",
    "            cur_region = extimg[r:r+filtr_row, c:c+filtr_col]\n",
    "            result[r, c] = np.sum(cur_region * filtr)\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2 3]\n",
      " [4 5 6]\n",
      " [7 8 9]]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "(array([[-24.]]), 'vs', array([[-24]]))"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conv2d(image, filtr, mode='valid'), \"vs\", convolve2d(image, filtr, mode='valid')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0. 0. 0. 0. 0.]\n",
      " [0. 1. 2. 3. 0.]\n",
      " [0. 4. 5. 6. 0.]\n",
      " [0. 7. 8. 9. 0.]\n",
      " [0. 0. 0. 0. 0.]]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[-13., -20., -17.],\n",
       "       [-18., -24., -18.],\n",
       "       [ 13.,  20.,  17.]])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conv2d(image, filtr, mode='same')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-13, -20, -17],\n",
       "       [-18, -24, -18],\n",
       "       [ 13,  20,  17]])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "convolve2d(image, filtr, mode='same', boundary='fill', fillvalue=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0. 0. 0. 0. 0. 0. 0.]\n",
      " [0. 0. 0. 0. 0. 0. 0.]\n",
      " [0. 0. 1. 2. 3. 0. 0.]\n",
      " [0. 0. 4. 5. 6. 0. 0.]\n",
      " [0. 0. 7. 8. 9. 0. 0.]\n",
      " [0. 0. 0. 0. 0. 0. 0.]\n",
      " [0. 0. 0. 0. 0. 0. 0.]]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[ -1.,  -4.,  -8.,  -8.,  -3.],\n",
       "       [ -4., -13., -20., -17.,  -6.],\n",
       "       [ -6., -18., -24., -18.,  -6.],\n",
       "       [  4.,  13.,  20.,  17.,   6.],\n",
       "       [  7.,  22.,  32.,  26.,   9.]])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conv2d(image, filtr, mode='full')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ -1,  -4,  -8,  -8,  -3],\n",
       "       [ -4, -13, -20, -17,  -6],\n",
       "       [ -6, -18, -24, -18,  -6],\n",
       "       [  4,  13,  20,  17,   6],\n",
       "       [  7,  22,  32,  26,   9]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "convolve2d(image, filtr, mode='full', boundary='fill', fillvalue=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# A 5x5 and V 3x3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = np.array([[17, 24, 1, 8, 15],\n",
    "              [23, 5, 7, 14, 16],\n",
    "              [4, 6, 13, 20, 22],\n",
    "              [10, 12, 19, 21, 3],\n",
    "              [11, 18, 25, 2, 9]], dtype=np.int)\n",
    "\n",
    "V = np.array([[1, 3, 1], [0, 5, 0], [2, 1, 2]], dtype=np.int)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## conv full mode"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 17,  75,  90,  35,  40,  53,  15],\n",
       "       [ 23, 159, 165,  45, 105, 137,  16],\n",
       "       [ 38, 198, 120, 165, 205, 197,  52],\n",
       "       [ 56,  95, 160, 200, 245, 184,  35],\n",
       "       [ 19, 117, 190, 255, 235, 106,  53],\n",
       "       [ 20,  89, 160, 210,  75,  90,   6],\n",
       "       [ 22,  47,  90,  65,  70,  13,  18]])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "convolve2d(A, V, mode='full', boundary='fill', fillvalue=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.  0.  0.  0.  0.  0.  0.  0.  0.]\n",
      " [ 0.  0.  0.  0.  0.  0.  0.  0.  0.]\n",
      " [ 0.  0. 17. 24.  1.  8. 15.  0.  0.]\n",
      " [ 0.  0. 23.  5.  7. 14. 16.  0.  0.]\n",
      " [ 0.  0.  4.  6. 13. 20. 22.  0.  0.]\n",
      " [ 0.  0. 10. 12. 19. 21.  3.  0.  0.]\n",
      " [ 0.  0. 11. 18. 25.  2.  9.  0.  0.]\n",
      " [ 0.  0.  0.  0.  0.  0.  0.  0.  0.]\n",
      " [ 0.  0.  0.  0.  0.  0.  0.  0.  0.]]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[ 17.,  75.,  90.,  35.,  40.,  53.,  15.],\n",
       "       [ 23., 159., 165.,  45., 105., 137.,  16.],\n",
       "       [ 38., 198., 120., 165., 205., 197.,  52.],\n",
       "       [ 56.,  95., 160., 200., 245., 184.,  35.],\n",
       "       [ 19., 117., 190., 255., 235., 106.,  53.],\n",
       "       [ 20.,  89., 160., 210.,  75.,  90.,   6.],\n",
       "       [ 22.,  47.,  90.,  65.,  70.,  13.,  18.]])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conv2d(A, V, mode='full')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## conv same mode"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[159, 165,  45, 105, 137],\n",
       "       [198, 120, 165, 205, 197],\n",
       "       [ 95, 160, 200, 245, 184],\n",
       "       [117, 190, 255, 235, 106],\n",
       "       [ 89, 160, 210,  75,  90]])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "convolve2d(A, V, mode='same', boundary='fill', fillvalue=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.  0.  0.  0.  0.  0.  0.]\n",
      " [ 0. 17. 24.  1.  8. 15.  0.]\n",
      " [ 0. 23.  5.  7. 14. 16.  0.]\n",
      " [ 0.  4.  6. 13. 20. 22.  0.]\n",
      " [ 0. 10. 12. 19. 21.  3.  0.]\n",
      " [ 0. 11. 18. 25.  2.  9.  0.]\n",
      " [ 0.  0.  0.  0.  0.  0.  0.]]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[159., 165.,  45., 105., 137.],\n",
       "       [198., 120., 165., 205., 197.],\n",
       "       [ 95., 160., 200., 245., 184.],\n",
       "       [117., 190., 255., 235., 106.],\n",
       "       [ 89., 160., 210.,  75.,  90.]])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conv2d(A, V, mode='same')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## conv mode valid"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[120, 165, 205],\n",
       "       [160, 200, 245],\n",
       "       [190, 255, 235]])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "convolve2d(A, V, mode='valid', boundary='fill', fillvalue=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[17 24  1  8 15]\n",
      " [23  5  7 14 16]\n",
      " [ 4  6 13 20 22]\n",
      " [10 12 19 21  3]\n",
      " [11 18 25  2  9]]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[120., 165., 205.],\n",
       "       [160., 200., 245.],\n",
       "       [190., 255., 235.]])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conv2d(A, V, mode='valid')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
